#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Last Update:

'''捕获http数据包, 只关注http返回值
'''

__revision__ = '0.1'
__author__ = 'lxd'

import pcap
import dpkt
import time
from gzip import GzipFile
try:
    from cStringIO import StringIO
except ImportError:
    from StringIO import StringIO
import binascii
from threadWithQuit import ThreadWithQuit
import tools

class CaptureThread(ThreadWithQuit):
    def __init__(self, log, dev, cap):
        ThreadWithQuit.__init__(self, log)
        self.dev = dev
        self.cap = cap

    def run(self):
        pc = pcap.pcap(self.dev)
        pc.setfilter('ip')
        while True:
            self.checkSet()
            if pc.stats()[0] != 0:
                self.cap.append(pc)

class WebCapture():
    def __init__(self,log):
        self.log = log
        self.src_ip = '123.129.194.'

    def getFixedCapture(self,network):
        '''固定网卡，例如
        network = r'\Device\NPF_{B57BC6C4-3724-4262-ABCA-A1D4E8E5C14E}'
        '''
        pc = pcap.pcap(network)
        pc.setfilter('ip')
        return pc

    def getFileCapture(self,file_name):
        '''解析pcap文件
        '''
        f = open(file_name, 'rb')
        pc = dpkt.pcap.Reader(f)
        pc.setfilter('ip')
        return pc

    def getCapture(self):
        """find available capture interface
        """
        def createCaptures(cap):
            devs = pcap.findalldevs()
            captures = []
            for dev in devs:
                capture = CaptureThread(self.log, dev, cap)
                capture.setDaemon(True)
                capture.start()
                captures.append(capture)
            return captures

        def stopCaptures(captures):
            for c in captures:
                c.stop()

        @tools.loopWithTime()
        def findCapture():
            return cap

        cap = []
        captures = createCaptures(cap)
        if findCapture():
            self.log.debug('find capture interface success')
            stopCaptures(captures)
            return cap[0]
        else:
            self.log.debug('find no capture interface')
            return None
    
    #def getCapture(self):
        #"""find available capture interface
        #"""
        #def createCaptures(cap):
            #devs = pcap.findalldevs()
            #captures = []
            #for dev in devs:
                #capture = CaptureThread(self.log, dev, cap)
                #capture.setDaemon(True)
                #capture.start()
                #captures.append(capture)
            #return captures

        #def stopCaptures(captures):
            #for c in captures:
                #c.stop()

        #cap = []
        #captures = createCaptures(cap)
        #times= 0
        #while True:
            #if cap:
                #self.log.debug('find capture interface success')
                #stopCaptures(captures)
                #return cap[0]
            #else:
                #times += 1 
                #time.sleep(1)
            #if times > 10:
                #self.log.debug('find no capture interface')
                #return None

    def __uncompress(self,body):
        compressedstream = StringIO(body)
        gzipper = GzipFile(fileobj=compressedstream)
        body = gzipper.read()
        gzipper.close()
        return body

    def processZip(self,stream):
        """如果zip则解压缩
        """
        try:
            data = dpkt.http.Response(stream)
            body = data.body
            content_encoding = data.headers.get('content-encoding')
            if content_encoding and content_encoding.strip().lower() == 'gzip':
                body = self.__uncompress(body)
            return body
        except Exception, msg:
            self.log.error(msg)
            self.log.error(stream)
            self.log.error(binascii.hexlify(stream))
            return stream

    def __filterWithTCP(self, eth):
        if eth.type != dpkt.ethernet.ETH_TYPE_IP:
            return False
        ip = eth.data
        if ip.p != dpkt.ip.IP_PROTO_TCP:
            return False
        return ip

    def __filterWithSrcIP(self, data, ip = ''):
        #过滤ip或ip组
        if ip:
            str_ip='%d.%d.%d.%d'%tuple(map(ord,list(data.src)))
            if not str_ip.startswith(ip):
                return False
        return True

    def getWholeStream(self, buf):
        """得到http返回头及返回信息，有线网络分开返回(可能会有n段)，无线网络作为一个整体返回
        """
        eth = dpkt.ethernet.Ethernet(buf)
        ip = self.__filterWithTCP(eth)
        if not ip:return None
        if not self.__filterWithSrcIP(ip, self.src_ip):return None

        tcp = ip.data
        stream = tcp.data
        return stream

    def parse(self, body):
        """需要重载，解析body，返回需要的数据结构
        """
        #capture.log.debug('#' * 20)
        #capture.log.debug(response)
        
        print body

    def process(self, pc):
        response = ''
        for ts,buf in pc:
            stream = self.getWholeStream(buf)
            if stream:
                if (stream[:4] == 'HTTP') and (response != ''):
                    body = self.processZip(response)
                    self.parse(body)
                    response = ''
                response += stream

from pyamf import remoting
class AMFCapture(WebCapture):
     def parseAMF3(self,body):
        data = binascii.hexlify(body)
        pos = data.find('000300000001')#AMF3特有格式
        if pos>-1:
            stream = binascii.unhexlify(data[pos:])
            envelope = remoting.decode(stream)
            response = envelope.bodies[0][1].body
            return response
        else:
            return None
   
if __name__ == '__main__':
    import config
    capture = WebCapture(config.log)
    pc = capture.getCapture()
    #pc = capture.getFileCapture(r'qq7x/doc/data_home.pcap')
    #pc = capture.getFileCapture(r'qq7x/doc/data_office.pcap')
    if pc:
        response = ''
        for ts,buf in pc:
            stream = capture.getWholeStream(buf)
            if stream:
                if (stream[:4] == 'HTTP') and (response != ''):
                    body = capture.processZip(response)
                    capture.parse(body)
                    response = ''
                response += stream

